﻿/*
 *  Copyright 2009 Duck Pond, Inc.
 *  http://www.duckpondinc.com/
 *  
 *  This file is part of Server Watch & Alert.
 *
 *  Server Watch & Alert is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  Server Watch & Alert is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Server Watch & Alert.  If not, see <http://www.gnu.org/licenses/>.
 *  
 * */

using System;
using System.Collections.Generic;
using System.Linq;
using DuckPond.ServerWatchAlert.Core.ResultActions;
using DuckPond.ServerWatchAlert.Core.TestActions;
using DuckPond.ServerWatchAlert.Core.Xml;

namespace DuckPond.ServerWatchAlert.Core
{
    public static class MonitorManager
    {
        /////////////////////
        // FIELDS
        /////////////
        #region
        private static Config _Config;
        private static Dictionary<string, TestAction> _TestActions;
        private static Dictionary<string, LinkedList<TestResult>> _TestResults;
        private static Dictionary<string, ResultAction> _ReportActions;
        #endregion


        /////////////////////
        // PROPERTIES
        /////////////
        #region
        internal static Config Configuration
        {
            get
            {
                return _Config;
            }
        }
        #endregion


        /////////////////////
        // METHODS
        /////////////
        #region
        /// <summary>
        /// Loads the XML config file from the specified path.
        /// </summary>
        /// <param name="path"></param>
        public static void LoadConfig(string path)
        {
            _Config = Config.Load(path);
            _TestActions = _Config.TestActions.ToDictionary(x => x.Name);
            _TestResults
                = _TestActions
                    .ToDictionary(
                        x => x.Key,
                        x => new LinkedList<TestResult>());
            _ReportActions
                = _Config.ResultActions.ToDictionary(x => x.Name);

        }

        /// <summary>
        /// Checks to see if it is time to perform any tests. UI or service code should
        /// be calling this method periodically to ensure tests are performed.
        /// </summary>
        public static void Tick()
        {
            //////
            // for each test.
            foreach (string key in _TestActions.Keys)
            {
                // when was this test last performed
                TestAction test = _TestActions[key];
                TestResult lastTest = _TestResults[key].LastOrDefault();
                DateTime dateLastTest = DateTime.MinValue;
                if (lastTest != null)
                {
                    dateLastTest = lastTest.TimeStamp;
                }

                // is it time to perform the next test?
                TestResult newTestResult = null;
                if (dateLastTest.Add(test.Interval) < DateTime.Now)
                {
                    DateTime now = DateTime.Now;

                    // perform the test action
                    newTestResult = test.PerformAction();
                    _TestResults[key].AddLast(newTestResult);

                    // perform result-action.
                    // todo: add support for multiple actions
                    if (_ReportActions.Count != 0)
                    {
                        ResultAction alertAction = _ReportActions.First().Value;
                        alertAction.PerformAction(newTestResult, _TestResults[key]);
                    }
                }
                else
                {
                    continue;
                }
            }

            // keep the results list short
            foreach (KeyValuePair<string, LinkedList<TestResult>> kvp in _TestResults)
            {
                while (kvp.Value.Count > 100)
                {
                    kvp.Value.RemoveFirst();
                }
            }
        }
        #endregion
    }
}
